"""
Database models for Ruiyun Cloud Documentation Platform.

Models:
- Documentation: Stores documentation entries
- Administrator: Stores admin user accounts
- AuditLog: Stores audit trail of admin actions
"""
from datetime import datetime
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash

# Initialize SQLAlchemy instance (will be initialized in app factory)
db = SQLAlchemy()


class Documentation(db.Model):
    """
    Documentation model - stores documentation entries viewable by public users.

    Fields:
        id: Primary key
        title: Document title (max 200 chars)
        content: Full document content (Markdown, HTML, or plain text)
        format: Content format ('markdown', 'html', 'text')
        created_at: Creation timestamp
        updated_at: Last modification timestamp
    """
    __tablename__ = 'documentation'

    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200), nullable=False, index=True)
    content = db.Column(db.Text, nullable=False)
    format = db.Column(db.String(20), nullable=False)
    category = db.Column(db.String(100), nullable=True, index=True)  # Document category
    is_locked = db.Column(db.Boolean, nullable=False, default=False, index=True)  # Is document locked for editing
    locked_by = db.Column(db.Integer, db.ForeignKey('administrator.id'), nullable=True)  # Admin who locked the document
    locked_at = db.Column(db.DateTime, nullable=True)  # When document was locked
    created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow, index=True)
    updated_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow)

    # Add CHECK constraint for format field
    __table_args__ = (
        db.CheckConstraint(
            format.in_(['markdown', 'html', 'text']),
            name='check_documentation_format'
        ),
    )

    def __repr__(self):
        return f'<Documentation {self.id}: {self.title[:30]}>'

    def to_dict(self):
        """Convert model to dictionary for JSON serialization."""
        return {
            'id': self.id,
            'title': self.title,
            'content': self.content,
            'format': self.format,
            'category': self.category,
            'is_locked': self.is_locked,
            'locked_by': self.locked_by,
            'locked_at': self.locked_at.isoformat() if self.locked_at else None,
            'created_at': self.created_at.isoformat() if self.created_at else None,
            'updated_at': self.updated_at.isoformat() if self.updated_at else None,
        }


class Administrator(db.Model):
    """
    Administrator model - stores admin user accounts with authentication credentials.

    Fields:
        id: Primary key
        username: Login username (unique)
        password_hash: Werkzeug PBKDF2-SHA256 hashed password
        created_at: Account creation timestamp
    """
    __tablename__ = 'administrator'

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(50), unique=True, nullable=False, index=True)
    password_hash = db.Column(db.String(255), nullable=False)
    created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)

    # Relationship to audit logs
    audit_logs = db.relationship('AuditLog', backref='administrator', lazy='dynamic')

    def set_password(self, password):
        """
        Hash and set the password for this administrator.

        Args:
            password: Plain text password (minimum 8 characters)
        """
        if len(password) < 8:
            raise ValueError("Password must be at least 8 characters long")
        self.password_hash = generate_password_hash(password, method='pbkdf2:sha256')

    def check_password(self, password):
        """
        Verify a password against the stored hash.

        Args:
            password: Plain text password to verify

        Returns:
            bool: True if password matches, False otherwise
        """
        return check_password_hash(self.password_hash, password)

    def __repr__(self):
        return f'<Administrator {self.id}: {self.username}>'

    def to_dict(self):
        """Convert model to dictionary (excluding password hash)."""
        return {
            'id': self.id,
            'username': self.username,
            'created_at': self.created_at.isoformat() if self.created_at else None,
        }


class AuditLog(db.Model):
    """
    AuditLog model - records all administrative actions for security audit trail.

    Fields:
        id: Primary key
        admin_id: Foreign key to Administrator
        action: Action type (e.g., 'login', 'create_doc', 'update_doc')
        resource_type: Type of resource affected (e.g., 'documentation')
        resource_id: ID of affected resource
        timestamp: When action occurred
        details: Optional JSON or text details (IP address, user agent, changes)
    """
    __tablename__ = 'audit_log'

    id = db.Column(db.Integer, primary_key=True)
    admin_id = db.Column(db.Integer, db.ForeignKey('administrator.id'), nullable=False, index=True)
    action = db.Column(db.String(50), nullable=False)
    resource_type = db.Column(db.String(50), nullable=True)
    resource_id = db.Column(db.Integer, nullable=True)
    timestamp = db.Column(db.DateTime, nullable=False, default=datetime.utcnow, index=True)
    details = db.Column(db.Text, nullable=True)

    # Composite index for resource lookups
    __table_args__ = (
        db.Index('idx_resource', 'resource_type', 'resource_id'),
    )

    def __repr__(self):
        return f'<AuditLog {self.id}: {self.action} by admin {self.admin_id}>'

    def to_dict(self):
        """Convert model to dictionary for JSON serialization."""
        return {
            'id': self.id,
            'admin_id': self.admin_id,
            'admin_username': self.administrator.username if self.administrator else None,
            'action': self.action,
            'resource_type': self.resource_type,
            'resource_id': self.resource_id,
            'timestamp': self.timestamp.isoformat() if self.timestamp else None,
            'details': self.details,
        }
